//
// Copyright (c) 1995 Molecular Structure Corporation
//
// RESTRICTED RIGHTS NOTICE SHORT FORM (JUNE 1987)
//
// Use, reproduction, or disclosure is subject to restrictions set
// forth in Contract No. W-31-109-ENG-38 and Contract No. 
// 943072401 with the University of Chicago, Operator of
// Argonne National Laboratory.
//
// CUInumberField.cc   Initial author: J.W. Pflugrath           16-Dec-1995
//    This file contains the methods to implement the user interface class
//    CUInumberField which implements a composite widget with label, textField
//    and scrollbar to receive number input from users.
/*
 *
 * Copyright (C) 2014 Rigaku Americas Corporation
 *                    9009 New Trails Drive
 *                    The Woodlands, TX, USA  77381
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice(s), this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice(s), this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the Rigaku Americas Corporation nor the 
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL RIGAKU AMERICAS CORPORATION BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
*/

//
// README: Portions of this file are merged at file generation
// time. Edits can be made *only* in between specified code blocks, look
// for keywords <Begin user code> and <End user code>.
//
/////////////////////////////////////////////////////////////
//
// Source file for CUInumberField
//
//    This file generated by Builder Xcessory 3.5.1.
//
//    This class is a user interface "component", as described
//    in "Object-Oriented Programming with C++ and OSF/Motif",
//    by Douglas Young, Prentice Hall, 1992. ISBN 0-13-630252-1
//
/////////////////////////////////////////////////////////////
#include <X11/StringDefs.h>
#include <Xm/Form.h>
#include <Xm/ScrollBar.h>
#include <Xm/TextF.h>
#include <Xm/Label.h>
#include <Xm/Frame.h>
#include "CUInumberField.h"

//
// Convenience functions from utilities file.
//
extern void RegisterBxConverters(XtAppContext);
extern XtPointer CONVERT(Widget, char *, char *, int, Boolean *);
extern XtPointer DOUBLE(double);
extern XtPointer SINGLE(float);
extern void MENU_POST(Widget, XtPointer, XEvent *, Boolean *);
extern Pixmap XPM_PIXMAP(Widget, char**);
extern void SET_BACKGROUND_COLOR(Widget, ArgList, Cardinal*, Pixel);


// Begin user code block <head> 
// End user code block <head> 

//
// This table is used to define class resources that are placed
// in app-defaults. This table is necessary so each instance
// of this class has the proper default resource values set.
// This eliminates the need for each instance to have
// its own app-defaults values. This table must be NULL terminated.
//
#if defined(cxx_bx_compat)

Boolean CUInumberField::_initAppDefaults = True;
UIAppDefault  CUInumberField::_appDefaults[] = {
    {"", NULL, "sensitive", NULL},
    {"scrollBar", NULL, "value", NULL},
    {"scrollBar", NULL, "minimum", NULL},
    {"scrollBar", NULL, "maximum", NULL},
    {"scrollBar", NULL, "pageIncrement", NULL},
    {"textField", NULL, "value", NULL},
    {"label", NULL, "labelString", NULL},
    {NULL, NULL, NULL, NULL}
};
#endif

// These are default resources for widgets in objects of this class
// All resources will be prepended by *<name> at instantiation,
// where <name> is the name of the specific instance, as well as the
// name of the baseWidget. These are only defaults, and may be overriden
// in a resource file by providing a more specific resource name

String  CUInumberField::_defaultCUInumberFieldResources[] = {
        NULL
};

//
// Old style constructor, for compatibility only.
//
CUInumberField::CUInumberField(const char *name, Widget parent) : 
    UIComponent(name)
{
    
    // Begin user code block <alt_constructor> 
    // End user code block <alt_constructor> 
    create(parent);
}

//
// Class constructor.
//
CUInumberField::CUInumberField(const char *name) : UIComponent(name)
{
    
    // Begin user code block <constructor> 

  m_fMul      = 1.0;
  m_fAdd      = 0.0;
  strcpy(m_a30cValue, "Unknown");
  strcpy(m_a30cFormat, "%.2f");
  m_poXhelp = NULL;

    // End user code block <constructor> 
}

//
// Minimal Destructor. Base class destroys widgets.
//
CUInumberField::~CUInumberField() 
{
    
    // Begin user code block <destructor> 
  if (m_poXhelp != NULL)
    {
      delete m_poXhelp;
      m_poXhelp = NULL;
    }
    // End user code block <destructor> 
    delete _clientDataStructs;
}

//
// Handle creation of all widgets in the class.
//
void CUInumberField::create(Widget parent) 
{
    Arg      args[256];
    Cardinal ac=0;
    
    //
    // Load any class-defaulted resources for this object.
    //
    setDefaultResources(parent, _defaultCUInumberFieldResources);
    
#if defined(cxx_bx_compat)
    //
    // Setup app-defaults fallback table if not already done.
    //
    if (_initAppDefaults)
    {
        initAppDefaults(parent, "CUInumberField", _appDefaults);
        _initAppDefaults = False;
    }
    //
    // Now set the app-defaults for this instance.
    //
    setAppDefaults(parent, _appDefaults);
#endif
    
    //
    // Register the converters for the widgets.
    //
    RegisterBxConverters(XtWidgetToApplicationContext(parent)); 
    XtInitializeWidgetClass(xmFormWidgetClass);
    XtInitializeWidgetClass(xmScrollBarWidgetClass);
    XtInitializeWidgetClass(xmTextFieldWidgetClass);
    XtInitializeWidgetClass(xmLabelWidgetClass);
    XtInitializeWidgetClass(xmFrameWidgetClass);
    
    //
    // Create an unmanaged widget as the top of the hierarchy.
    //
    
    ac = 0;
    XtSetArg(args[ac], XmNresizePolicy, XmRESIZE_GROW); ac++;
    XtSetArg(args[ac], XmNx, 1052); ac++;
    XtSetArg(args[ac], XmNy, 198); ac++;
    XtSetArg(args[ac], XmNwidth, 100); ac++;
    XtSetArg(args[ac], XmNheight, 110); ac++;
    _CUInumberField = XmCreateForm(parent,
        _name,
        args, 
        ac);
    
    _w = _CUInumberField;
    //
    // Install callback to guard against unexpected widget destruction..
    //
    installDestroyHandler();
    
    ac = 0;
    XtSetArg(args[ac], XmNhighlightOnEnter, True); ac++;
    XtSetArg(args[ac], XmNorientation, XmHORIZONTAL); ac++;
    XtSetArg(args[ac], XmNx, 2); ac++;
    XtSetArg(args[ac], XmNy, 83); ac++;
    XtSetArg(args[ac], XmNwidth, 96); ac++;
    XtSetArg(args[ac], XmNheight, 25); ac++;
    _scrollBar = XmCreateScrollBar(_CUInumberField,
        "scrollBar",
        args, 
        ac);
    XtManageChild(_scrollBar);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNincrementCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNdecrementCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNpageIncrementCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNpageDecrementCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNtoTopCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNtoBottomCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_scrollBar,
        XmNdragCallback,
        CUInumberField::vScrollBarCBCallback,
        (XtPointer)_clientDataStructs);
    
    ac = 0;
    XtSetArg(args[ac], XmNhighlightOnEnter, True); ac++;
    XtSetArg(args[ac], XmNx, 2); ac++;
    XtSetArg(args[ac], XmNy, 48); ac++;
    XtSetArg(args[ac], XmNwidth, 96); ac++;
    XtSetArg(args[ac], XmNheight, 35); ac++;
    _textField = XmCreateTextField(_CUInumberField,
        "textField",
        args, 
        ac);
    XtManageChild(_textField);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_textField,
        XmNactivateCallback,
        CUInumberField::vTextFieldCBCallback,
        (XtPointer)_clientDataStructs);
    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = this;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_textField,
        XmNlosingFocusCallback,
        CUInumberField::vTextFieldCBCallback,
        (XtPointer)_clientDataStructs);
    
    ac = 0;
    XtSetArg(args[ac], XmNtraversalOn, False); ac++;
    XtSetArg(args[ac], XmNrecomputeSize, True); ac++;
    XtSetArg(args[ac], XmNx, 2); ac++;
    XtSetArg(args[ac], XmNy, 2); ac++;
    XtSetArg(args[ac], XmNwidth, 96); ac++;
    XtSetArg(args[ac], XmNheight, 46); ac++;
    _label = XmCreateLabel(_CUInumberField,
        "label",
        args, 
        ac);
    XtManageChild(_label);
    
    ac = 0;
    XtSetArg(args[ac], XmNnavigationType, XmNONE); ac++;
    XtSetArg(args[ac], XmNtraversalOn, False); ac++;
    XtSetArg(args[ac], XmNx, 0); ac++;
    XtSetArg(args[ac], XmNy, 0); ac++;
    _frame = XmCreateFrame(_CUInumberField,
        "frame",
        args, 
        ac);
    XtManageChild(_frame);
    
    ac = 0;
    XtSetArg(args[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
    XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNbottomWidget, _frame); ac++;
    XtSetArg(args[ac], XmNleftWidget, _frame); ac++;
    XtSetArg(args[ac], XmNrightWidget, _frame); ac++;
    XtSetArg(args[ac], XmNtopOffset, 0); ac++;
    XtSetArg(args[ac], XmNbottomOffset, 2); ac++;
    XtSetArg(args[ac], XmNleftOffset, 2); ac++;
    XtSetArg(args[ac], XmNrightOffset, 2); ac++;
    XtSetArg(args[ac], XmNresizable, False); ac++;
    XtSetValues(_scrollBar, args, ac);
    
    ac = 0;
    XtSetArg(args[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
    XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
    XtSetArg(args[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNbottomWidget, _scrollBar); ac++;
    XtSetArg(args[ac], XmNleftWidget, _frame); ac++;
    XtSetArg(args[ac], XmNrightWidget, _frame); ac++;
    XtSetArg(args[ac], XmNtopOffset, 0); ac++;
    XtSetArg(args[ac], XmNbottomOffset, 0); ac++;
    XtSetArg(args[ac], XmNleftOffset, 2); ac++;
    XtSetArg(args[ac], XmNrightOffset, 2); ac++;
    XtSetArg(args[ac], XmNresizable, False); ac++;
    XtSetValues(_textField, args, ac);
    
    ac = 0;
    XtSetArg(args[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
    XtSetArg(args[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
    XtSetArg(args[ac], XmNtopWidget, _frame); ac++;
    XtSetArg(args[ac], XmNbottomWidget, _textField); ac++;
    XtSetArg(args[ac], XmNleftWidget, _frame); ac++;
    XtSetArg(args[ac], XmNrightWidget, _frame); ac++;
    XtSetArg(args[ac], XmNtopOffset, 2); ac++;
    XtSetArg(args[ac], XmNbottomOffset, 0); ac++;
    XtSetArg(args[ac], XmNleftOffset, 2); ac++;
    XtSetArg(args[ac], XmNrightOffset, 2); ac++;
    XtSetValues(_label, args, ac);
    
    ac = 0;
    XtSetArg(args[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
    XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
    XtSetArg(args[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
    XtSetArg(args[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
    XtSetArg(args[ac], XmNtopOffset, 0); ac++;
    XtSetArg(args[ac], XmNbottomOffset, 0); ac++;
    XtSetArg(args[ac], XmNleftOffset, 0); ac++;
    XtSetArg(args[ac], XmNrightOffset, 0); ac++;
    XtSetValues(_frame, args, ac);
    
    // Begin user code block <endcreate> 

    // Get the string in the textField, if it begins with a % character
    // then use that as the format
    char *pcFormat;
    pcFormat = XmTextFieldGetString(_textField);
    if (pcFormat[0] == '%')
      {
	strcpy(m_a30cFormat, pcFormat);

	// Get value in scrollBar widget and set textField

	int nValue;
	XtVaGetValues(_scrollBar, XmNvalue, &nValue, NULL);
	vSetValue((float) nValue * m_fMul + m_fAdd);
      }
    XtFree(pcFormat);

    
#if (XmVersion >= 1002)
    {
    m_poXhelp = new CXhelp(_w);

    _clientDataStructs = new UICallbackStruct;
    _clientDataStructs->object = (UIComponent *)m_poXhelp;
    _clientDataStructs->client_data = (XtPointer)0;
    XtAddCallback(_textField,
        XmNfocusCallback,
        CXhelp::vPostOneLineCBCallback,
        (XtPointer)_clientDataStructs);
    XtAddCallback(_textField,
        XmNlosingFocusCallback,
        CXhelp::vUnpostOneLineCBCallback,
        (XtPointer)_clientDataStructs);
  }
#endif    
    // End user code block <endcreate> 
}

//
// Classname access.
//
const char *const CUInumberField::className()
{
    return ("CUInumberField");
}

void CUInumberField::vScrollBarCBCallback(Widget w, 
		XtPointer clientData, XtPointer callData)
{
    UICallbackStruct *data = (UICallbackStruct *) clientData;
    CUInumberField *obj = (CUInumberField *)data->object;
    obj->vScrollBarCB(w, data->client_data, callData);
}

void CUInumberField::vScrollBarCB (Widget w, XtPointer clientData, XtPointer callData)
{
    
    // Begin user code block <vScrollBarCB> 

  XmScrollBarCallbackStruct *pCBS =  (XmScrollBarCallbackStruct *)callData;
  vSetValue((float) pCBS->value * m_fMul + m_fAdd);

    // End user code block <vScrollBarCB> 
}

void CUInumberField::vTextFieldCBCallback(Widget w, 
		XtPointer clientData, XtPointer callData)
{
    UICallbackStruct *data = (UICallbackStruct *) clientData;
    CUInumberField *obj = (CUInumberField *)data->object;
    obj->vTextFieldCB(w, data->client_data, callData);
}

void CUInumberField::vTextFieldCB (Widget w, XtPointer clientData, XtPointer callData)
{
    
    // Begin user code block <vTextFieldCB> 

  XmAnyCallbackStruct *pCBS = (XmAnyCallbackStruct *)callData;  

  if ( (pCBS->reason == XmCR_ACTIVATE) || (pCBS->reason == XmCR_LOSING_FOCUS) )
    {
      // We are leaving textfield, so read text in widget and
      // put the scrollBar at the correct place
      
      int nMin, nMax, nSlide;
      float fTemp = (fGetValue() - m_fAdd) / m_fMul;
      int   nTemp = (int) fTemp;

      // Before setting scrollbar value, check that it fits in the
      // min and max.

      XtVaGetValues(_scrollBar, XmNminimum, &nMin, XmNmaximum, &nMax, 
		    XmNsliderSize, &nSlide, NULL);
      if (nTemp > nMax-nSlide)
	{
	  XtVaSetValues(_scrollBar, XmNmaximum, nTemp+nSlide, NULL);
	}
      if (nTemp < nMin)
	{
	  XtVaSetValues(_scrollBar, XmNminimum, nTemp, NULL);
	}
      XtVaSetValues(_scrollBar, XmNvalue, nTemp, NULL);
    }

  // End user code block <vTextFieldCB> 
}
void
CUInumberField::set_cuinumberfield_width(XtPointer value)
{
    Arg	args[10];
    Cardinal ac;
    
    ac = 0;
    XtSetArg(args[ac], XmNwidth, value); ac++;
    XtSetValues(_CUInumberField, args, ac);
}
void
CUInumberField::set_cuinumberfield_height(XtPointer value)
{
    Arg	args[10];
    Cardinal ac;
    
    ac = 0;
    XtSetArg(args[ac], XmNheight, value); ac++;
    XtSetValues(_CUInumberField, args, ac);
}

// Begin user code block <tail> 

float
CUInumberField::fGetValue()
{
  float fTemp;
  (void) pcGetValue();
  sscanf(m_a30cValue, "%f", &fTemp);
  return( fTemp );
}

int
CUInumberField::nGetValue()
{
  int nTemp;
  (void) pcGetValue();
  sscanf(m_a30cValue, "%d", &nTemp);
  return( nTemp );
}

char*
CUInumberField::pcGetValue()
{
  char *pcText;
  pcText = XmTextFieldGetString(_textField);
  strcpy(m_a30cValue, pcText);
  XtFree (pcText);
  return( (char *) m_a30cValue );
}

void
CUInumberField::vSetValue(char* pcValue)
{
  // First set the textField to the string value

  XmTextFieldSetString(_textField, pcValue);

  // Put the scrollBar at the correct place
  int nScroll;
  nScroll = (int) (fGetValue() * m_fMul  +  m_fAdd);
  XtVaSetValues(_scrollBar, XmNvalue, nScroll, NULL);
}

void
CUInumberField::vSetValue(int nValue)
{
  // First convert integer to char* and ...
  char acTemp[30];
  sprintf(acTemp, "%d", nValue);
  vSetValue(acTemp);
}

void
CUInumberField::vSetValue(float fValue)
{
  // First convert float to char* and ...
  char acTemp[30];
  sprintf(acTemp, m_a30cFormat, fValue);
  vSetValue(acTemp);
}

void
CUInumberField::vSetFormat(char* pcFormat)
{
  strcpy(m_a30cFormat, pcFormat);
}

void
CUInumberField::vSetMulAdd(const float fMul, const float fAdd)
{
  m_fMul = fMul;
  m_fAdd = fAdd;
}

void
CUInumberField::vGetMulAdd(float *pfMul, float *pfAdd)
{
  *pfMul = m_fMul;
  *pfAdd = m_fAdd;
}
// End user code block <tail> 
